package com.hoshiibuy.neo4j.util;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.hoshiibuy.neo4j.node.RNode;
import com.hoshiibuy.neo4j.node.Tenant;
import com.hoshiibuy.neo4j.node.relation.REdge;
import lombok.extern.slf4j.Slf4j;
import org.neo4j.driver.v1.Record;
import org.neo4j.driver.v1.Session;
import org.neo4j.driver.v1.StatementResult;
import org.neo4j.driver.v1.Value;
import org.neo4j.driver.v1.types.Node;

@Slf4j
public class Neo4jUtil {


    /**
     * 创建租户
     *
     * @param tenant
     * @throws Exception
     */
    public static void createTenant(ObjectMapper mapper, Session session, Tenant tenant) throws Exception {

        // 查node是否已經存在了，不存在則創建
        tenant.getProperties().put("uuid", tenant.getUuid());
        String propertiesString = mapper.writeValueAsString(tenant.getProperties());
        String cypherSql = String.format("create (n:多租户 %s)", propertiesString);
        log.info(cypherSql);
        session.run(cypherSql);
        log.info("创建租户：" + tenant.getLabel() + "成功！");

    }

    /**
     * 创建平台
     *
     * @param rNode
     * @throws Exception
     */
    public static void createPlatform(ObjectMapper mapper, Session session, RNode rNode) throws Exception {
        RNode srcNode = queryNode(mapper, session, rNode);
        // 查node是否已經存在了，不存在則創建
        if (srcNode == null) {
            String propertiesString = mapper.writeValueAsString(rNode.getProperties());
            String cypherSql = String.format("create (n:平台%s)\n" +
                    "with n\n" +
                    "match (n),(m:多租户{name:'%s'})\n" +
                    "create (n)<-[r:租户平台]-(m)", propertiesString, rNode.getLabel());
            log.info(cypherSql);
            StatementResult result = session.run(cypherSql);
            log.info(result.toString());
            while (result.hasNext()) {
                Record record = result.next();

            }


            log.info("创建平台：" + rNode.getLabel() + "成功！");
        } else {
            log.info("平台已存在，跳过创建");
        }
    }

    /**
     * 新建组织架构
     *
     * @param rNode
     * @throws Exception
     */
    public static void createOrganization(ObjectMapper mapper, Session session, RNode rNode) throws Exception {
        RNode srcNode = queryNode(mapper, session, rNode);
        // 查node是否已經存在了，不存在則創建
        if (srcNode == null) {
            String propertiesString = mapper.writeValueAsString(rNode.getProperties());
            String cypherSql = String.format("create (n:组织架构%s)\n" +
                    "with n\n" +
                    "match (n),(m{name:'%s'})\n" +
                    "create (n)<-[:租户组织]-(m)", propertiesString, rNode.getLabel());
            log.info(cypherSql);
            session.run(cypherSql);
            log.info("组织架构：" + rNode.getLabel() + "成功！");
        } else {
            log.info("组织架构已存在，跳过创建");
        }
    }

    /**
     * 创建角色
     *
     * @param rNode
     * @throws Exception
     */
    public static void createRole(ObjectMapper mapper, Session session, RNode rNode) throws Exception {
        RNode srcNode = queryNode(mapper, session, rNode);
        // 查node是否已經存在了，不存在則創建
        if (srcNode == null) {
            String propertiesString = mapper.writeValueAsString(rNode.getProperties());
            String cypherSql = String.format("create (n:角色体系%s)\n" +
                    "with n\n" +
                    "match (n),(m:组织架构{name:'%s'})\n" +
                    "create (m)-[:组织角色]->(n)", propertiesString, rNode.getLabel());
            log.info(cypherSql);
            session.run(cypherSql);
            log.info("创建角色：" + rNode.getLabel() + "成功！");
        } else {
            log.info("角色已存在，跳过创建");
        }
    }

    /**
     * 创建权限
     *
     * @param rNode
     * @throws Exception
     */
    public static void createPermission(ObjectMapper mapper, Session session, RNode rNode) throws Exception {
        RNode srcNode = queryNode(mapper, session, rNode);
        // 查node是否已經存在了，不存在則創建
        if (srcNode == null) {
            String propertiesString = mapper.writeValueAsString(rNode.getProperties());
            String cypherSql = String.format("create (n:权限体系%s)\n" +
                    "with n\n" +
                    "match (n),(m:角色体系{name:'%s'})\n" +
                    "create (n)-[:角色权限]->(m)", propertiesString, rNode.getLabel());
            log.info(cypherSql);
            session.run(cypherSql);
            log.info("创建权限：" + rNode.getLabel() + "成功！");
        } else {
            log.info("权限已存在，跳过创建");
        }
    }

    /**
     * 创建用户区
     *
     * @param rNode
     * @throws Exception
     */
    public static void createUserArea(ObjectMapper mapper, Session session, RNode rNode) throws Exception {
        RNode srcNode = queryNode(mapper, session, rNode);
        // 查node是否已經存在了，不存在則創建
        if (srcNode == null) {
            String propertiesString = mapper.writeValueAsString(rNode.getProperties());
            String cypherSql = String.format("create (n:用户体系%s)\n" +
                    "with n\n" +
                    "match (n),(m:平台{name:'%s'})\n" +
                    "create (n)<-[:平台用户]-(m)", propertiesString, rNode.getLabel());
            log.info(cypherSql);
            session.run(cypherSql);
            log.info("创建用户区：" + rNode.getLabel() + "成功！");
        } else {
            log.info("用户区已存在，跳过创建");
        }
    }

    /**
     * 创建用户
     *
     * @param rNode
     * @throws Exception
     */
    public static void createUser(ObjectMapper mapper, Session session, RNode rNode) throws Exception {
        RNode srcNode = queryNode(mapper, session, rNode);
        // 查node是否已經存在了，不存在則創建
        if (srcNode == null) {
            String propertiesString = mapper.writeValueAsString(rNode.getProperties());
            String cypherSql = String.format("create (n:用户成员%s)\n" +
                    "with n\n" +
                    "match (n),(m:用户体系{code:n.code})\n" +
                    "create (n)<-[:用户成员]-(m)\n" +
                    "with n\n" +
                    "match (n),(n1:用户成员{serial:n.recomserial})\n" +
                    "create (n)<-[:用户发展]-(n1)", propertiesString);
            log.info(cypherSql);
            session.run(cypherSql);
            log.info("创建用户区：" + rNode.getLabel() + "成功！");
        } else {
            log.info("用户区已存在，跳过创建");
        }
    }

    /**
     * 创建员工
     *
     * @param rNode
     * @throws Exception
     */
    public static void createStaff(ObjectMapper mapper, Session session, RNode rNode) throws Exception {
        RNode srcNode = queryNode(mapper, session, rNode);
        // 查node是否已經存在了，不存在則創建
        if (srcNode == null) {
            String propertiesString = mapper.writeValueAsString(rNode.getProperties());
            String cypherSql = String.format("create (n:员工体系%s)\n" +
                    "with n\n" +
                    "match (n),(m:组织架构{name:'%s'})\n" +
                    "create (n)-[:组织员工]->(m)", propertiesString, rNode.getLabel());
            log.info(cypherSql);
            session.run(cypherSql);
            log.info("创建员工：" + rNode.getLabel() + "成功！");
        } else {
            log.info("员工已存在，跳过创建");
        }
    }


    /**
     * 分配员工角色
     *
     * @param
     * @throws Exception
     */
    public static void createstaffRole(ObjectMapper mapper, Session session, String StaffName, String roleName) throws Exception {
        String cypherSql = String.format("MATCH (a),(b)\n" +
                "WHERE a.name = '%s' AND b.name = '%s'\n" +
                "CREATE (a)-[r:员工角色]->(b)\n" +
                "RETURN r;", StaffName, roleName);
        log.info(cypherSql);
        session.run(cypherSql);
        log.info("员工角色：" + StaffName + "成功！");

    }

    /**
     * 创建合作机构
     *
     * @param rNode
     * @throws Exception
     */
    public static void createCooperationOrg(ObjectMapper mapper, Session session, RNode rNode) throws Exception {
        RNode srcNode = queryNode(mapper, session, rNode);
        // 查node是否已經存在了，不存在則創建
        if (srcNode == null) {
            String propertiesString = mapper.writeValueAsString(rNode.getProperties());
            String cypherSql = String.format("create (n:合作机构体系%s)\n" +
                    "with n\n" +
                    "match (n),(m:平台{name:'%s')\n" +
                    "create (n)<-[:平台合作]-(m)", propertiesString, rNode.getLabel());
            log.info(cypherSql);
            session.run(cypherSql);
            log.info("创建合作机构：" + rNode.getLabel() + "成功！");
        } else {
            log.info("合作机构已存在，跳过创建");
        }
    }

    /**
     * 创建节点
     *
     * @param rNode
     * @throws Exception
     */
    public static void createNode(ObjectMapper mapper, Session session, RNode rNode) throws Exception {
        RNode srcNode = queryNode(mapper, session, rNode);
        // 查node是否已經存在了，不存在則創建
        if (srcNode == null) {
            String propertiesString = mapper.writeValueAsString(rNode.getProperties());
            String cypherSql = String.format("create (:%s%s)", rNode.getLabel(), propertiesString);
            log.info(cypherSql);
            session.run(cypherSql);
            log.info("创建节点：" + rNode.getLabel() + "成功！");
        } else {
            log.info("节点已存在，跳过创建");
        }
    }

    /**
     * 创建关系
     *
     * @param srcNode
     * @param tarNode
     * @throws Exception
     */
    public static void createRelation(ObjectMapper mapper, Session session, RNode srcNode, RNode tarNode)
            throws Exception {
        REdge edge = queryRelation(mapper, session, srcNode, tarNode);
        if (edge == null) {
            edge = srcNode.getEdge();
            String propertiesString = mapper.writeValueAsString(edge.getProperties());
            String cypherSql = String.format("match(a),(b) where a.uuid=%d and b.uuid=%d create (a)-[r:%s %s]->(b)",
                    srcNode.getUuid(), tarNode.getUuid(), edge.getName(), propertiesString);
            log.info(cypherSql);
            session.run(cypherSql);
            log.info("创建关系：" + edge.getName() + "成功！");
        } else {
            log.info("关系已存在，跳过创建");
        }
    }

    /**
     * 查询节点
     *
     * @param rNode
     * @return
     */
    public static RNode queryNode(ObjectMapper mapper, Session session, RNode rNode) {

        RNode node = null;
        String cypherSql = String.format("match(n:%s) where n.uuid = '2200' return n", rNode.getLabel(), rNode.getUuid() + "");
        StatementResult result = session.run(cypherSql);
        if (result.hasNext()) {
            Record record = result.next();
            for (Value value : record.values()) {
                /**
                 * 结果里面只要类型为节点的值
                 */
                if (value.type().name().equals("NODE")) {
                    Node noe4jNode = value.asNode();
                    node = new RNode();
                    node.setLabel(rNode.getLabel());
                    node.setProperties(noe4jNode.asMap());

                }
            }
        }
        return node;
    }

    /**
     * 查询关系
     *
     * @param tarNode
     * @return
     */
    public static REdge queryRelation(ObjectMapper mapper, Session session, RNode srcNode, RNode tarNode) {
        REdge edge = srcNode.getEdge();
        String cypherSql = String.format("match(n)-[r:%s]-(b) where n.uuid = %d and b.uuid = %d return r",
                edge.getName(), srcNode.getUuid(), tarNode.getUuid());
        StatementResult result = session.run(cypherSql);
        if (result.hasNext()) {
            return edge;
        }
        return null;
    }
}
